'use strict';

const fs = require('fs'); // 导入文件系统模块
const path = require('path'); // 导入路径模块
const webpack = require('webpack'); // 导入 webpack 模块
const resolve = require('resolve'); // 导入 resolve 模块
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 导入 HtmlWebpackPlugin 插件
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); // 导入 CaseSensitivePathsPlugin 插件
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); // 导入 InlineChunkHtmlPlugin 插件
const TerserPlugin = require('terser-webpack-plugin'); // 导入 TerserPlugin 插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 导入 MiniCssExtractPlugin 插件
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); // 导入 CssMinimizerPlugin 插件
const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); // 导入 WebpackManifestPlugin 插件
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); // 导入 InterpolateHtmlPlugin 插件
const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); // 导入 WorkboxWebpackPlugin 插件
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); // 导入 ModuleScopePlugin 插件
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); // 导入 getCSSModuleLocalIdent 模块
const ESLintPlugin = require('eslint-webpack-plugin'); // 导入 ESLintPlugin 插件
const paths = require('./paths'); // 导入路径配置
const modules = require('./modules'); // 导入模块配置
const getClientEnvironment = require('./env'); // 导入客户端环境配置
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); // 导入 ModuleNotFoundPlugin 插件
const ForkTsCheckerWebpackPlugin = // 导入 ForkTsCheckerWebpackPlugin 插件
  process.env.TSC_COMPILE_ON_ERROR === 'true'
    ? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin')
    : require('react-dev-utils/ForkTsCheckerWebpackPlugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); // 导入 ReactRefreshWebpackPlugin 插件

const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash'); // 导入创建环境哈希的模块

// Source maps are resource heavy and can cause out of memory issue for large source files.
// 是否使用源映射，可以在构建过程中提供更好的错误信息和调试功能
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

// 导入 React Refresh 运行时
const reactRefreshRuntimeEntry = require.resolve('react-refresh/runtime');
const reactRefreshWebpackPluginRuntimeEntry = require.resolve(
  '@pmmmwh/react-refresh-webpack-plugin'
);
const babelRuntimeEntry = require.resolve('babel-preset-react-app');
const babelRuntimeEntryHelpers = require.resolve(
  '@babel/runtime/helpers/esm/assertThisInitialized',
  { paths: [babelRuntimeEntry] }
);
const babelRuntimeRegenerator = require.resolve('@babel/runtime/regenerator', {
  paths: [babelRuntimeEntry],
});

// 是否内联运行时代码到 bundle 中
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';

// 是否将 ESLint 错误作为警告展示
const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === 'true';

// 是否禁用 ESLint 插件
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true';

// 图片内联大小限制
const imageInlineSizeLimit = parseInt(
  process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
);

// 检查是否配置了 TypeScript
const useTypeScript = fs.existsSync(paths.appTsConfig);

// 检查是否存在 Tailwind 配置文件
const useTailwind = fs.existsSync(
  path.join(paths.appPath, 'tailwind.config.js')
);

// 获取未编译服务工作线程的路径
const swSrc = paths.swSrc;

// CSS 文件的正则表达式
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;

// 是否启用新的 JSX 转换
const hasJsxRuntime = (() => {
  if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
    return false;
  }

  try {
    require.resolve('react/jsx-runtime');
    return true;
  } catch (e) {
    return false;
  }
})();

// 这是生产和开发配置。
// 它专注于开发人员体验、快速重建和最小捆绑。
module.exports = function (webpackEnv) {
  const isEnvDevelopment = webpackEnv === 'development'; // 是否开发环境
  const isEnvProduction = webpackEnv === 'production'; // 是否生产环境

  // 是否启用生产环境下的性能分析
  const isEnvProductionProfile =
    isEnvProduction && process.argv.includes('--profile');

  // 将 `paths.publicUrlOrPath` 作为环境变量传递给我们的应用程序
  // 在 `index.html` 中作为 %PUBLIC_URL%，在 JavaScript 中作为 process.env.PUBLIC_URL。
  // 省略末尾斜杠，因为 %PUBLIC_URL%/xyz 比 %PUBLIC_URL%xyz 更好看。
  const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));

  // 是否使用 React 刷新
  const shouldUseReactRefresh = env.raw.FAST_REFRESH;

  // 获取样式加载器的通用函数
  const getStyleLoaders = (cssOptions, preProcessor) => {
    const loaders = [
      isEnvDevelopment && require.resolve('style-loader'),
      isEnvProduction && {
        loader: MiniCssExtractPlugin.loader,
        options: paths.publicUrlOrPath.startsWith('.')
          ? { publicPath: '../../' }
          : {},
      },
      {
        loader: require.resolve('css-loader'),
        options: cssOptions,
      },
      {
        loader: require.resolve('postcss-loader'),
        options: {
          postcssOptions: {
            ident: 'postcss',
            config: false,
            plugins: !useTailwind
              ? [
                  'postcss-flexbugs-fixes',
                  [
                    'postcss-preset-env',
                    {
                      autoprefixer: {
                        flexbox: 'no-2009',
                      },
                      stage: 3,
                    },
                  ],
                ]
              : [],
          },
          sourceMap: isEnvProduction && shouldUseSourceMap,
        },
      },
    ].filter(Boolean);
    if (preProcessor) {
      loaders.push(
        {
          loader: require.resolve('resolve-url-loader'),
          options: {
            sourceMap: isEnvProduction && shouldUseSourceMap,
            root: paths.appSrc,
          },
        },
        {
          loader: require.resolve(preProcessor),
          options: {
            sourceMap: true,
          },
        }
      );
    }
    return loaders;
  };

  return {
    // webpack 配置的入口点
    entry: [
      // 开发环境下，为了启用 React 刷新，需要添加以下两个条目。
      shouldUseReactRefresh &&
        require.resolve('react-dev-utils/webpackHotDevClient'),
      shouldUseReactRefresh && reactRefreshRuntimeEntry,
      shouldUseReactRefresh && reactRefreshWebpackPluginRuntimeEntry,
      // 应用程序的入口文件
      paths.appIndexJs,
    ].filter(Boolean),
    // 配置如何输出文件
    output: {
      // 输出文件的目录
      path: isEnvProduction ? paths.appBuild : undefined,
      // 输出文件的名称
      filename: isEnvProduction
        ? 'static/js/[name].[contenthash:8].js'
        : isEnvDevelopment && 'static/js/bundle.js',
      // chunk 文件的名称
      chunkFilename: isEnvProduction
        ? 'static/js/[name].[contenthash:8].chunk.js'
        : isEnvDevelopment && 'static/js/[name].chunk.js',
      // 相对于 HTML 页面的 URL
      publicPath: paths.publicUrlOrPath,
      // 是否为 webpack5
      futureEmitAssets: true,
      // 每个块的 JSONP 函数
      jsonpFunction: `webpackJsonp${appPackageJson.name}`,
      // 通过 crossOriginLoading 设置加载跨域资源的属性
      crossOriginLoading: 'anonymous',
      // 如果启用 sourcemap，则在这里指定
      ...(isEnvProduction
        ? {
            // 生成源映射的方式
            sourceMapFilename: 'static/js/[name].[contenthash:8].map',
            // 在文件名中包含 sourceMap 映射
            chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
          }
        : {}),
    },
    // 配置 webpack 如何寻找文件
    resolve: {
      modules: ['node_modules', paths.appNodeModules].concat(
        modules.additionalModulePaths || []
      ),
      // 这些是 Node.js 模块的别名，可以让你更轻松地导入模块，或者减少到导入的路径。
      // 它们在 `import` 语句中被使用。
      alias: {
        'react-native': 'react-native-web',
      },
      // 这些字段用于在导入时省略后缀名。
      extensions: paths.moduleFileExtensions
        .map((ext) => `.${ext}`)
        .filter((ext) => useTypeScript || !ext.includes('ts')),
      // 是否强制导入文件时使用大小写敏感模式
      plugins: [new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson])],
      // 从缓存中解析请求以节省时间
      // 这会影响模块 ID，而不是消除完全缓存的 ID。
      unsafeCache: true,
      // 不根据导入的目录中是否存在 `package.json` 文件来导入目录。
      // 这使得以相同的顺序导入文件时，目录路径不变。
      // 此外，此选项可防止webpack解析时进入非项目目录。
      symlinks: false,
      // 提供给解析器的其他解析选项。
      // webpack默认值如下：
      // 确保将所有模块重新编译，而不是使用缓存！
      cacheWithContext: false,
    },
    // 配置 webpack 如何寻找 loaders
    resolveLoader: {
      modules: ['node_modules', paths.ownNodeModules],
      // 扩展文件名
      extensions: ['/index.js', '.js'],
      // 解析 loaders 时不跳过任何目录
      moduleExtensions: ['-loader'],
      // 在导入时可省略的文件扩展名
      plugins: [
        // 在 node_modules 外部的模块不解析为 webpack loaders
        new ModuleScopePlugin(paths.appNodeModules, [paths.ownNodeModules]),
      ],
    },
    // 如何处理模块
    module: {
      strictExportPresence: true,
      rules: [
        { parser: { requireEnsure: false } },
        {
          // 配置 ES6+ 语法和 JSX 语法的转换
          oneOf: [
            // 对于 CSS 文件，采用不同的处理方式
            {
              test: cssRegex,
              // 使用 'oneOf' 匹配 loaders，只能匹配一个 loader，匹配到一个就不再往下匹配
              oneOf: [
                // 针对 CSS modules 的处理
                {
                  test: cssModuleRegex,
                  // 使用 `getStyleLoaders` 函数获取处理 CSS 的 loaders
                  use: getStyleLoaders({
                    importLoaders: 1,
                    sourceMap: isEnvProduction && shouldUseSourceMap,
                    modules: {
                      getLocalIdent: getCSSModuleLocalIdent,
                    },
                  }),
                  sideEffects: true,
                },
                // 默认的 CSS 处理
                {
                  use: getStyleLoaders({
                    importLoaders: 1,
                    sourceMap: isEnvProduction && shouldUseSourceMap,
                  }),
                  sideEffects: true,
                },
              ],
            },
            // 对于 SASS 文件的处理
            {
              test: sassRegex,
              // 使用 'oneOf' 匹配 loaders
              oneOf: [
                // 针对 CSS modules 的处理
                {
                  test: sassModuleRegex,
                  // 使用 `getStyleLoaders` 函数获取处理 CSS 的 loaders，并加入 sass-loader
                  use: getStyleLoaders(
                    {
                      importLoaders: 3,
                      sourceMap: isEnvProduction && shouldUseSourceMap,
                      modules: {
                        getLocalIdent: getCSSModuleLocalIdent,
                      },
                    },
                    'sass-loader'
                  ),
                  sideEffects: true,
                },
                // 默认的 SASS 处理
                {
                  // 使用 `getStyleLoaders` 函数获取处理 CSS 的 loaders，并加入 sass-loader
                  use: getStyleLoaders(
                    {
                      importLoaders: 3,
                      sourceMap: isEnvProduction && shouldUseSourceMap,
                    },
                    'sass-loader'
                  ),
                  sideEffects: true,
                },
              ],
            },
            // 对于 LESS 文件的处理
            {
              test: lessRegex,
              oneOf: [
                // 针对 CSS modules 的处理
                {
                  test: lessModuleRegex,
                  // 使用 `getStyleLoaders` 函数获取处理 CSS 的 loaders，并加入 less-loader
                  use: getStyleLoaders(
                    {
                      importLoaders: 3,
                      sourceMap: isEnvProduction && shouldUseSourceMap,
                      modules: {
                        getLocalIdent: getCSSModuleLocalIdent,
                      },
                    },
                    'less-loader'
                  ),
                  sideEffects: true,
                },
                // 默认的 LESS 处理
                {
                  // 使用 `getStyleLoaders` 函数获取处理 CSS 的 loaders，并加入 less-loader
                  use: getStyleLoaders(
                    {
                      importLoaders: 3,
                      sourceMap: isEnvProduction && shouldUseSourceMap,
                    },
                    'less-loader'
                  ),
                  sideEffects: true,
                },
              ],
            },
            // 处理图片文件
            {
              test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
              type: 'asset',
              parser: {
                dataUrlCondition: {
                  maxSize: imageInlineSizeLimit,
                },
              },
            },
            // 处理字体文件
            {
              loader: require.resolve('file-loader'),
              exclude: [/\.js$/, /\.html$/, /\.json$/],
              type: 'asset/resource',
            },
            // Babel 预处理，处理 JS、JSX 文件
            {
              test: /\.(js|mjs|jsx|ts|tsx)$/,
              include: paths.appSrc,
              loader: require.resolve('babel-loader'),
              options: {
                customize: require.resolve(
                  'babel-preset-react-app/webpack-overrides'
                ),
                // 使用 Babel 配置文件
                babelrc: false,
                configFile: false,
                presets: [
                  [
                    require.resolve('babel-preset-react-app'),
                    {
                      runtime: hasJsxRuntime ? 'automatic' : 'classic',
                    },
                  ],
                ],
                // 使用 @babel/plugin-transform-runtime 处理 async/await 和更好地代码重用
                plugins: [
                  [
                    require.resolve('@babel/plugin-transform-runtime'),
                    {
                      version: require('@babel/runtime/package.json').version,
                      regenerator: true,
                    },
                  ],
                  // React 刷新插件
                  shouldUseReactRefresh &&
                    require.resolve('react-refresh/babel'),
                ].filter(Boolean),
                // 在开发环境下启用 sourceMaps
                sourceMaps: isEnvProduction && shouldUseSourceMap,
                // 在生产环境下禁用 `fork-ts-checker-webpack-plugin` 并在构建时完成类型检查
                // 确保 `process.env.NODE_ENV` 在所有模块中保持一致，并且在生产模式下启用tree shaking
                cacheDirectory: true,
                cacheCompression: false,
                compact: isEnvProduction,
              },
            },
            // 解析 Graphql 文件
            {
              test: /\.(graphql|gql)$/,
              exclude: /node_modules/,
              loader: 'graphql-tag/loader',
            },
            // 忽略样式文件中的 TypeScript 类型错误
            ...(disableESLintPlugin
              ? []
              : [
                  {
                    test: /\.(js|mjs|jsx|ts|tsx)$/,
                    enforce: 'pre',
                    use: [
                      {
                        options: {
                          formatter: require.resolve(
                            'react-dev-utils/eslintFormatter'
                          ),
                          eslintPath: require.resolve('eslint'),
                          emitWarning: emitErrorsAsWarnings,
                        },
                        loader: require.resolve('eslint-loader'),
                      },
                    ],
                    include: paths.appSrc,
                  },
                ]),
          ],
        },
      ],
    },
    // 优化配置
    optimization: {
      minimize: isEnvProduction, // 是否启用压缩
      minimizer: [
        // 压缩 JS 文件
        new TerserPlugin({
          terserOptions: {
            parse: {
              // 我们希望 terser 能够解析 ES8 语法，但不希望它重写 ES5 方法，因为会使开发环境的性能降低。
              ecma: 8,
            },
            compress: {
              ecma: 5,
              warnings: false, // 在生产环境下关闭警告
              comparisons: false,
              inline: 2, // 内联简单的函数，设置为 2 或更高的值，以在较小的函数中进行内联
            },
            mangle: {
              safari10: true,
            },
            output: {
              ecma: 5,
              comments: false, // 移除所有注释
              ascii_only: true, // 仅输出 ascii 字符集
            },
          },
          // 启用文件缓存
          cache: true,
          // 开启多进程压缩
          parallel: true,
          // 在生产环境下启用 sourceMaps
          sourceMap: shouldUseSourceMap,
        }),
        // 压缩 CSS 文件
        new CssMinimizerPlugin({
          minimizerOptions: {
            preset: [
              'default',
              {
                discardComments: { removeAll: true }, // 移除所有注释
              },
            ],
            // 在生产环境下启用 sourceMaps
            sourceMap: shouldUseSourceMap,
          },
        }),
      ],
      // 在生产环境下，为每个 chunk 创建一个独立的运行时文件，以便缓存策略更好地工作。
      runtimeChunk: {
        name: (entrypoint) => `runtime-${entrypoint.name}`,
      },
      // 合并模块
      splitChunks: {
        chunks: 'all',
        // 缓存组
        cacheGroups: {
          // 代码分离缓存组
          commons: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
          },
        },
      },
    },
    // 配置 webpack 插件
    plugins: [
      // 生成一个带有内容哈希的文件
      new WebpackManifestPlugin({
        fileName: 'asset-manifest.json',
        publicPath: paths.publicUrlOrPath,
        generate: (seed, files, entrypoints) => {
          const manifestFiles = files.reduce((manifest, file) => {
            manifest[file.name] = file.path;
            return manifest;
          }, seed);
          const entrypointFiles = entrypoints.main.filter(
            (fileName) => !fileName.endsWith('.map')
          );

          return {
            files: manifestFiles,
            entrypoints: entrypointFiles,
          };
        },
      }),
      // 生成 HTML 文件
      new HtmlWebpackPlugin({
        inject: true,
        template: paths.appHtml,
        ...(isEnvProduction
          ? {
              minify: {
                removeComments: true, // 移除注释
                collapseWhitespace: true, // 移除空格
                removeRedundantAttributes: true, // 移除冗余属性
                useShortDoctype: true, // 使用短的 doctype
                removeEmptyAttributes: true, // 移除空的属性
                removeStyleLinkTypeAttributes: true, // 移除 style 和 link 标签的 type 属性
                keepClosingSlash: true, // 保留尾部斜杠
                minifyJS: true, // 压缩 script 标签中的 JS 代码
                minifyCSS: true, // 压缩 style 标签中的 CSS 代码
                minifyURLs: true, // 压缩 URL
              },
            }
          : undefined),
      }),
      // 将环境变量注入到应用程序中
      new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
      // 在控制台输出项目中找不到模块的警告
      new ModuleNotFoundPlugin(paths.appPath),
      // 检查你的代码是否符合预设的规则
      !disableESLintPlugin &&
        new ESLintPlugin({
          // 使用 ESLint 的 cache 功能
          cache: true,
          // 指定 cache 的路径
          cacheLocation: path.resolve(
            paths.appNodeModules,
            '.cache/.eslintcache'
          ),
          // 在 webpack 构建期间启用 ESLint 检查
          // 它会增加构建时间，但也会减少不必要的错误
          eslintPath: require.resolve('eslint'),
          // 确保 ESLint 在所有模块中保持一致，并且在生产模式下启用tree shaking
          // https://github.com/facebook/create-react-app/issues/3871
          context: paths.appSrc,
          // 使用默认的格式化程序输出 lint 结果到控制台
          formatter: require.resolve('react-dev-utils/eslintFormatter'),
          // 是否将 ESLint 错误作为警告输出
          emitWarning: emitErrorsAsWarnings,
          // 如果在构建过程中找到 lint 错误，不会中断构建
          emitError: !emitErrorsAsWarnings,
          // 指定 ESLint 配置文件的路径
          overrideConfigFile: paths.eslintConfig,
          // 指定要使用的插件
          plugins: ['eslint-plugin-react'],
        }),
      // 显示构建进度的插件
      new webpack.ProgressPlugin(),
      // 在运行时检测到模块发生变化时，自动更新页面
      shouldUseReactRefresh && new ReactRefreshWebpackPlugin(),
      // 在构建过程中检查 TypeScript 错误
      useTypeScript &&
        new ForkTsCheckerWebpackPlugin({
          typescript: resolve.sync('typescript', {
            basedir: paths.appNodeModules,
          }),
          async: isEnvDevelopment,
          useTypescriptIncrementalApi: true,
          checkSyntacticErrors: true,
          tsconfig: paths.appTsConfig,
          reportFiles: [
            '**',
            '!**/__tests__/**',
            '!**/?(*.)(spec|test).*',
            '!**/src/setupProxy.*',
            '!**/src/setupTests.*',
          ],
          silent: true,
          // 指定 cache 的路径
          formatter: 'basic',
          formatterOptions: {
            // 常规输出信息
            // 比如错误的详细信息、错误行和列、文件路径等
            showSummary: false,
            // 诊断信息，指示 TypeScript 做了哪些事情以及它的内部状态
            // 比如有多少文件被处理，多少已经完成等等
            showDiagnosticItems: true,
            // 如果该字段为true，则在每次请求之后都会打印一个新的分隔线
            // 默认为false
            // verbose: false,
          },
        }),
      // 生成一个带有最终服务工作脚本的服务工作
      swSrc &&
        new WorkboxWebpackPlugin.InjectManifest({
          swSrc,
          dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
          exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
          maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
        }),
      // 开发环境下，允许你的应用程序在编译时中断
      isEnvDevelopment &&
        new CaseSensitivePathsPlugin({
          // 默认为 false
          // 如果设为 true，则控制台将显示信息，以提醒你是否存在大小写问题
          // 同时，应用程序将无法运行
          // 开发人员需要根据具体情况去解决错误
          debug: false,
        }),
      // 在开发环境下，在发生文件变化时，重新加载页面
      isEnvDevelopment &&
        shouldUseReactRefresh &&
        new webpack.HotModuleReplacementPlugin(),
      // 将所有 css 抽取到一个文件中
      isEnvProduction &&
        new MiniCssExtractPlugin({
          // 输出文件名
          filename: 'static/css/[name].[contenthash:8].css',
          // 输出文件的名称
          chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
          // 忽略生成的文件中包含的顺序
          ignoreOrder: true,
        }),
      // 内联主要的 webpack 运行时脚本到 HTML 中
      isEnvProduction &&
        shouldInlineRuntimeChunk &&
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
      // 自动推断文件的类型（例如当导入不带文件扩展名的文件时，自动推断其类型）
      // 并为其添加文件扩展名（例如，将 ./foo 转换为 ./foo.js）
      new webpack.ProvidePlugin({
        process: 'process/browser',
      }),
    ].filter(Boolean),
    // 配置 webpack 如何输出性能提示
    performance: false,
    // 是否启用缓存和缓存的持久化
    cache: {
      type: 'filesystem',
      buildDependencies: {
        config: [__filename],
      },
    },
    // 启用控制台输出的详细程度
    stats: {
      all: false,
      colors: true,
      errors: true,
      warnings: true,
      moduleTrace: true,
      errorDetails: true,
      builtAt: true,
      timings: true,
    },
    // 控制台输出的日志级别
    // 'info': console.log
    // 'none': 不输出任何信息
    // 'error': 只输出错误信息
    // 'warn': 输出警告信息
    // 'trace': 输出警告和错误信息
    // 'verbose': 输出警告、错误和其他信息
    // 'log': 输出警告、错误、其他信息和 webpack log
    logging: 'info',
    // 关闭 chokidar（适用于 Windows）
    watchOptions: {
      ignored: /node_modules/,
    },
    // 统计信息的来源
    recordsPath: path.join(paths.appPath, 'node_modules/.cache/webpack-records'),
    // 记录性能分析信息
    profile: isEnvProductionProfile,
    // 启用严格模式
    // 严格模式不允许混用未声明的全局变量
    // 它会抛出错误并中止编译
    mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
    // 是否启用严格模式
    // 在严格模式下，会检测到更多的错误，并阻止在生产构建时生成损坏的文件
    bail: isEnvProduction,
    // 在发生错误时中止构建
    // 这将避免在生产环境下的部署过程中，将损坏的代码部署到生产环境中。
    // 即使在发生错误时，它也会生成损坏的代码。这对于在 CI/CD 环境中检查错误非常有用。
    devtool: isEnvProduction
      ? shouldUseSourceMap
        ? 'source-map'
        : false
      : isEnvDevelopment && 'cheap-module-source-map',
    // 使用自定义的解析配置
    // resolve: {},
    // 设置用于浏览器的默认环境
    target: isEnvProduction ? ['web', 'browserslist:defaults'] : 'web',
    // 指定编译后文件的编码格式
    // utf-8 是最通用的编码格式
    // latin1 用于所有不适合 utf-8 的场景
    // Node.js 默认使用 utf-8 编码
    node: {
      global: false, // Node.js 全局变量和全局对象
      __filename: false, // 当前模块的文件名，如 /path/to/file.js
      __dirname: false, // 当前模块的目录名，如 /path/to
      // 可选的配置，模块化导入的路径
      // 默认情况下，Webpack 会解析所有的路径。可以通过指定一些不需要解析的路径来减少构建时间
      // 例如，设置为 { amqplib: 'empty' } 将不解析 amqplib 中的模块
      // 更多信息请查阅 https://webpack.js.org/configuration/node/
      module: 'empty',
      process: 'mock',
      Buffer: false, // Buffer 类用于处理二进制数据
      setImmediate: false, // setImmediate 是一个 Node.js 环境提供的全局函数
    },
    // 此选项允许我们添加额外的日志记录选项。例如，当启用 silent 时，一些插件可能不输出任何消息。
    // 启用 silent 意味着如果没有明确禁用，插件的标准日志记录将被静音。
    infrastructureLogging: {
      level: 'warn',
      // 有关更多选项，请参见 https://webpack.js.org/configuration/infrastructurelogging/#options
    },
  };
};
